package com.mk.aline.aspectjdemo.aspectjs;

import android.util.Log;

import com.mk.aline.aspectjdemo.SecurityCheckAnnotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * Author：Administrator
 * Data: 2018/8/14 0014 16:35
 */

@Aspect
public class DemoAspect {
    private static final String TAG = "test_DemoAspect";

    /**
     * @Pointcut：pointcut也变成了一个注解，这个注解是针对一个函数的，比如此处的logForActivity() 其实它代表了这个pointcut的名字。如果是带参数的pointcut，则把参数类型和名字放到
     * 代表pointcut名字的logForActivity中，然后在@Pointcut注解中使用参数名。
     * 基本和以前一样，只是写起来比较奇特一点。后面我们会介绍带参数的例子
     */
    @Pointcut("execution(* com.mk.aline.aspectjdemo.MainActivity.onCreate(..)) ||"
            + "execution(* com.mk.aline.aspectjdemo.MainActivity.onStart(..))")
    public void logForActvity() {
    }


    /**
     * @Before：这就是Before的advice，对于after，after -returning，和after-throwing。对于的注解格式为
     * @After，@AfterReturning，@AfterThrowing。Before后面跟的是pointcut名字，然后其代码块由一个函数来实现。比如此处的log。
     */
    @Before("logForActvity()")
    public void log(JoinPoint joinPoint) {
        //对于使用Annotation的AspectJ而言，JoinPoint就不能直接在代码里得到多了，而需要通过
        //参数传递进来。
        Log.e(TAG, joinPoint.toShortString());
    }


    /**
     * 来看这个Pointcut，首先，它在选择Jpoint的时候，把@SecurityCheckAnnotation使用上了，这表明所有那些public的，
     * 并且携带有这个注解的API都是目标JPoint
     * 接着，由于我们希望在函数中获取注解的信息，所有这里的poincut函数有一个参数，参数类型是
     * SecurityCheckAnnotation，参数名为ann
     * 这个参数我们需要在后面的advice里用上，所以pointcut还使用了@annotation(ann)这种方法来告诉
     * AspectJ，这个ann是一个注解
     *
     * 注意： 这里有一个需要注意的点：
     *   SecurityCheckAnnotation 相应的注解类如果和该类在同包，则可以直接写SecurityCheckAnnotation，
     *   如果不在则写SecurityCheckAnnotation全路径
     */
    @Pointcut("execution(@com.mk.aline.aspectjdemo.SecurityCheckAnnotation public * *..*.*(..)) && @annotation(ann)")
    public void checkPermssion(SecurityCheckAnnotation ann) {
    }


    /**
     * 接下来是advice，advice的真正功能由check函数来实现，这个check函数第二个参数就是我们想要
     * 的注解。在实际运行过程中，AspectJ会把这个信息从JPoint中提出出来并传递给check函数。
     */
    @After("checkPermssion(securityCheckAnnotation)")
    public void check(JoinPoint joinPoint, SecurityCheckAnnotation securityCheckAnnotation) {
        //从注解信息中获取声明的权限。
        String neededPermission = securityCheckAnnotation.declaredPermission();
        Log.e(TAG, joinPoint.toShortString());
        Log.e(TAG, "\tneeded permission is " + neededPermission);
        return;
    }


    @Before("execution(private * *..*.Main*.testAOP(..))")
    public void aopTestExection(JoinPoint mJoinPoint) {
        Log.e("testAopEx0", mJoinPoint.getSignature().toString());
        Log.e("testAopEx1", mJoinPoint.toShortString());
    }

    @Before("call(private * *..*.Main*.testAOP(..))")
    public void aopTestCall(JoinPoint mJoinPoint) {
        Log.e("testAopCall0", mJoinPoint.getSignature().toString());
        Log.e("testAopCall1", mJoinPoint.toShortString());
    }


    @Around("call(private * *..*.Main*.testAround(..))")
    public void aopTestAround(ProceedingJoinPoint mProceedingJoinPoint) throws Throwable {
        String key = mProceedingJoinPoint.getSignature().toString();
        Log.e("testAround0", " first " + key);
        mProceedingJoinPoint.proceed();
        Log.e("testAround1", "after " + key);
    }
}
